/* 
 * File:   ParserXML.cpp
 * Author: fibrizo
 * 
 * Created on 24 de mayo de 2014, 23:04
 */

#include "common_ParserXML.h"
#include <string>
#include <iostream>
#include <fstream>
#include "tinyxml2.h"
#include <map>

using std::cout;
using std::endl;
using std::ofstream;
using std::string;
using std::vector;
using std::map;
using tinyxml2::XMLDocument;
using namespace tinyxml2;

typedef struct vector<string> vectorS;

/************************************************************************/
/*                             CONSTRUCTORES                            */
/************************************************************************/


ParserXML::ParserXML() {
}

ParserXML::ParserXML(const ParserXML& orig) {
}

/************************************************************************/
/*                             METODOS PRIVADOS                         */
/************************************************************************/

void ParserXML::agregarDato(string etiqueta, string dato, XMLElement* primero, XMLDocument& doc) {
   XMLElement* nuevoElemento = doc.NewElement(etiqueta.c_str());
   XMLText* texto = doc.NewText(dato.c_str());
   nuevoElemento->InsertEndChild(texto);
   primero->InsertEndChild(nuevoElemento);
}

/************************************************************************/
/*                             METODOS PUBLICOS                         */
/************************************************************************/

vectorS ParserXML::cargarDatos(string rutaArchivo) {
    XMLDocument doc;
    vectorS datos;
    int codigo = doc.LoadFile(rutaArchivo.c_str());
    if (codigo != XML_NO_ERROR) {
        throw "No se pudo abrir";
    }

    XMLElement* primero = doc.FirstChildElement();
    XMLElement* elemento;
    XMLElement* anterior;
    elemento = primero->FirstChildElement();
    anterior = elemento;
    const char* valor = elemento->GetText();
    datos.push_back(string(valor));
    string cadena;
    elemento = elemento->NextSiblingElement();
   
    while (elemento) {
        while (elemento->FirstChildElement()) {
            elemento = elemento->FirstChildElement();
        }
        valor = elemento->GetText();

        if (valor) {
            cadena = string(valor);
            datos.push_back(cadena);
        }
        anterior = elemento;
        elemento = elemento->NextSiblingElement();
        
        while (!elemento) {
            XMLNode* nodo = anterior;
            if (!nodo->Parent()) return datos;
            elemento = (nodo->Parent())->ToElement();
            anterior = elemento;
            if (elemento == primero) return datos;
            elemento = elemento->NextSiblingElement();
        }

    }
    return datos;
}

// Este metodo solo es utilizado por el Editor del Juego, por lo tanto
// su uso fuera de este contexto puede ocasionar resultados no esperados.
// Parametros:
// rutaArchivo: string con la ruta del archivo a leer.
// nombreCampania: nombre de la campania a almacenar.
// datos: vector de de vectores de strings que espera los siguientes datos en cada posicion:
//      pos0: numero de nivel
//      pos1: nombre del nivel
//      pos2: cantidad de zombies verdes.
//      pos3: cantidad de zombies azules.
//      pos4: cantidad de zombies rojos.
//      pos5: cantidad de plantas
//      pos6: largo del tileMap
//      pos7: tile map del nivel
bool ParserXML::guardarDatos(string rutaArchivo, vectorS datosCampania, vector<vectorS> datosNiveles) {
   XMLDocument doc;
   string cabecera = string("<?xml version=\"1.0\" ?>");
   XMLElement* primero = doc.NewElement("Campania");
   doc.InsertFirstChild(primero);
   XMLElement* nuevoElemento;
   XMLElement* actual;
   vectorS datosNivel;
   
   vectorS etiquetasCampania = {"Nombre", "RutaImagen", "Dificultad", "CantidadJugadores"};
   vectorS etiquetasNivel = {"Nivel","Numero", "Nombre", "Zombies", "Verdes", 
                                    "Azules", "Rojos", "Plantas", "LargoMapa", "TileMap"};
   
   for(unsigned int i = 0; i < datosCampania.size(); i++)
       agregarDato(etiquetasCampania[i], datosCampania[i], primero, doc);
   
   for(unsigned int i = 0; i < datosNiveles.size(); i++) {
       datosNivel = datosNiveles[i];
       nuevoElemento = doc.NewElement((etiquetasNivel[0]).c_str());
       primero->InsertEndChild(nuevoElemento);
       
       // Agrego el Numero del Nivel
       actual = nuevoElemento;
       agregarDato(etiquetasNivel[1], datosNivel[0], actual, doc);
       agregarDato(etiquetasNivel[2], datosNivel[1], actual, doc);
       
       // Agrego las cantidades de Zombies
       nuevoElemento =doc.NewElement((etiquetasNivel[3]).c_str());
       actual->InsertEndChild(nuevoElemento);
       actual = nuevoElemento;
       agregarDato(etiquetasNivel[4], datosNivel[2], actual, doc);
       agregarDato(etiquetasNivel[5], datosNivel[3], actual, doc);
       agregarDato(etiquetasNivel[6], datosNivel[4], actual, doc);
       
       // Plantas
       actual = (actual->Parent())->ToElement();
       agregarDato(etiquetasNivel[7], datosNivel[5], actual, doc);
       agregarDato(etiquetasNivel[8], datosNivel[6], actual, doc);
       agregarDato(etiquetasNivel[9], datosNivel[7], actual, doc);  
        
   }

   XMLPrinter printer;
   ofstream archivo;
   archivo.open (rutaArchivo, ofstream::out | ofstream::app);
   doc.Print(&printer);
   archivo << cabecera << endl;
   archivo << printer.CStr();
   archivo.close();
   return true;
}

vector<vector<string> > ParserXML::cargarNiveles(string rutaArchivo) {
    vector<string> datos = cargarDatos(rutaArchivo);
    vector<vector<string> > niveles;
    unsigned int i = 10;    
    while (i < datos.size()) {
        vector<string> nivel = {datos[i-6], datos[i-5], datos[i], datos[i + 1]};
        niveles.push_back(nivel);
        i += 8;
    }
    return niveles;
}

vector<string> ParserXML::cargarDatosIncialesCampania(string rutaArchivo) {
    vector<string> datos = cargarDatos(rutaArchivo);
    vector<string> datosCampania = {datos[0], datos[1], datos[2], datos[3]};
    return datosCampania;
}

/************************************************************************/
/*                               DESTRUCTOR                             */
/************************************************************************/

ParserXML::~ParserXML() {
}

